﻿#include "HnrjitCheckBox.h"
#include "HnrjitContainer.h"
#include "HnrjitControl.h"
#include "HnrjitDialog.h"
#include "HnrjitImaging.h"
#include "HnrjitRadioBox.h"

CHnrjitContainer::CHnrjitContainer(CHnrjitDialog* pParentDialog)
	: CHnrjitWigdet()
	, m_crBackColor(RGB(0xf0, 0xf0, 0xf0))
	, m_hbmpBackImage(NULL)
	, m_pFocusControl(NULL)
	, m_pParentDialog(pParentDialog)
{
	m_pParentDialog->AddContainer(this);
}

CHnrjitContainer::~CHnrjitContainer()
{
	m_pParentDialog->RemoveContainer(this);
	DeleteObject(m_hbmpBackImage);
	RemoveAllControl();
}

void CHnrjitContainer::SetAttribute(const TiXmlElement* pxElement, HZIP hZipRes /*= NULL*/)
{
	CHnrjitWigdet::SetAttribute(pxElement, hZipRes);

	const CHAR* pszValue;
	if (pszValue = pxElement->Attribute("BackColor"))
	{
		const CHAR* pszColor = (pszValue[0] == '#') ? pszValue + 1 : pszValue;
		LONG lColor = strtol(pszColor, NULL, 16);
		SetBackColor(lColor);
	}
	if (pszValue = pxElement->Attribute("BorderColor"))
	{
		const CHAR* pszColor = (pszValue[0] == '#') ? pszValue + 1 : pszValue;
		LONG lColor = strtol(pszColor, NULL, 16);
		SetBorderColor(lColor);
	}
	if (pszValue = pxElement->Attribute("BackImage"))
	{
		CAtlArray<TCHAR> caResult;
		const TCHAR* pszBackImage = CHnrjitImaging::Utf8ToLocal(pszValue, &caResult);
		if (pszBackImage) SetBackImage(CHnrjitImaging::LoadFromFile(pszBackImage, hZipRes));
	}
}

BOOL CHnrjitContainer::AddControl(CHnrjitControl* pControl)
{
	if (pControl && !pControl->m_pContainer)
	{
		pControl->m_pContainer = this;
		m_arrControls.Add(pControl);
		return TRUE;
	}
	return FALSE;
}

BOOL CHnrjitContainer::AddControl(UINT nIndex, CHnrjitControl* pControl)
{
	if (pControl && !pControl->m_pContainer)
	{
		if (nIndex == m_arrControls.GetCount())
		{
			pControl->m_pContainer = this;
			m_arrControls.Add(pControl);
		}
		else if (nIndex < m_arrControls.GetCount())
		{
			pControl->m_pContainer = this;
			m_arrControls.InsertAt(nIndex, pControl);
			return TRUE;
		}
	}
	return FALSE;
}

BOOL CHnrjitContainer::RemoveControl(CHnrjitControl* pControl)
{
	ATLASSERT(pControl && pControl->m_pContainer == this);

	for (size_t i = 0; i < m_arrControls.GetCount(); i++)
	{
		if (pControl == m_arrControls[i])
		{
			pControl->m_pContainer = NULL;
			m_arrControls.RemoveAt(i);
			return TRUE;
		}
	}
	return FALSE;
}

BOOL CHnrjitContainer::RemoveControl(UINT nIndex)
{
	if (nIndex < m_arrControls.GetCount())
	{
		CHnrjitControl* pControl = m_arrControls[nIndex];
		pControl->m_pContainer = NULL;
		m_arrControls.RemoveAt(nIndex);
		return TRUE;
	}
	return FALSE;
}

void CHnrjitContainer::RemoveAllControl()
{
	for (size_t i = 0; i < m_arrControls.GetCount(); i++)
	{
		CHnrjitControl* pControl = m_arrControls[i];
		pControl->m_pContainer = NULL;
	}
	m_arrControls.RemoveAll();
}

CHnrjitControl* CHnrjitContainer::GetControl(UINT nIndex) const
{
	if (nIndex < m_arrControls.GetCount())
	{
		return m_arrControls[nIndex];
	}
	return NULL;
}

LONG CHnrjitContainer::GetControlIndex(CHnrjitControl* pControl) const
{
	ATLASSERT(pControl && pControl->m_pContainer == this);

	for (size_t i = 0; i < m_arrControls.GetCount(); i++)
	{
		if (pControl == m_arrControls[i])
		{
			return (LONG) i;
		}
	}
	return (LONG) -1;
}

UINT CHnrjitContainer::GetControlCount() const
{
	return m_arrControls.GetCount();
}

CHnrjitControl* CHnrjitContainer::GetActivate() const
{
	return m_pFocusControl;
}

BOOL CHnrjitContainer::SetActivate(CHnrjitControl* pControl)
{
	if (pControl)
	{
		if (GetControlIndex(pControl) != INFINITE)
		{
			// 控件必须在窗口内
			if (m_pFocusControl != pControl)
			{
				// 控件未被激活过
				if (m_pFocusControl)
				{
					// 释放掉已激活控件
					m_pFocusControl->OnKillFocus(pControl);
					SetChecked(m_pFocusControl, FALSE);
				}
				pControl->OnSetFocus(m_pFocusControl);
				m_pFocusControl = pControl;
				SetChecked(m_pFocusControl, TRUE);
			}
			return TRUE;
		}
	}
	else
	{
		if (m_pFocusControl)
		{
			// 释放掉已激活控件
			m_pFocusControl->OnKillFocus(NULL);
			m_pFocusControl = NULL;
		}
		return TRUE;
	}

	return FALSE;
}

BOOL CHnrjitContainer::SetActivate(UINT nIndex)
{
	if (nIndex < m_arrControls.GetCount())
	{
		if (m_pFocusControl != m_arrControls[nIndex])
		{
			if (m_pFocusControl)
			{
				m_pFocusControl->OnKillFocus(m_arrControls[nIndex]);
				SetChecked(m_pFocusControl, FALSE);
			}
			m_arrControls[nIndex]->OnSetFocus(m_pFocusControl);
			m_pFocusControl = m_arrControls[nIndex];
			SetChecked(m_pFocusControl, TRUE);
		}
		return TRUE;
	}

	return FALSE;
}

COLORREF CHnrjitContainer::GetBackColor() const
{
	return m_crBackColor;
}

void CHnrjitContainer::SetBackColor(COLORREF crBackColor)
{
	ATLASSERT(m_dwThreadID == GetCurrentThreadId());
	if (m_crBackColor != crBackColor)
	{
		m_crBackColor = crBackColor;
		Invalidate(m_rcGeometry);
	}
}

COLORREF CHnrjitContainer::GetBorderColor() const
{
	return m_3dBorderColor;
}

void CHnrjitContainer::SetBorderColor(COLORREF crBorderColor)
{
	ATLASSERT(m_dwThreadID == GetCurrentThreadId());
	if (m_3dBorderColor != crBorderColor)
	{
		m_3dBorderColor = crBorderColor;
		Invalidate(m_rcGeometry);
	}
}

void CHnrjitContainer::SetBackImage(CComPtr<IImage> imgPicture, BOOL bResize /*= FALSE*/)
{
	ATLASSERT(m_dwThreadID == GetCurrentThreadId());
	DeleteObject(m_hbmpBackImage);
	if (imgPicture)
	{
		if (bResize)
		{
			ImageInfo ImgInfo;
			if (imgPicture->GetImageInfo(&ImgInfo) == S_OK)
			{
				m_rcGeometry = CRect(GetLocation(), CSize(ImgInfo.Width, ImgInfo.Height));
			}
		}
		m_hbmpBackImage = CHnrjitImaging::CreateHBitmap(imgPicture, GetSize());
	}
	Invalidate(m_rcGeometry);
}

void CHnrjitContainer::SetChecked(CHnrjitControl* pControl, BOOL isChecked)
{
	ATLASSERT(pControl && pControl->m_pContainer == this);

	if (pControl->IsKindOf(CLSID_HNRJITRADIOBOX))
	{
		// 如果控件系”单选框“或”复选框“
		CHnrjitRadioBox* pRadioBox = static_cast<CHnrjitRadioBox*>(pControl);
		pRadioBox->SetChecked(TRUE);
	}
	if (pControl->IsKindOf(CLSID_HNRJITCHECKBOX))
	{
		CHnrjitCheckBox* pCheckBox = static_cast<CHnrjitCheckBox*>(pControl);
		pCheckBox->SetChecked(TRUE);
	}
}

void CHnrjitContainer::OnClicked(CHnrjitControl* pControl)
{
	m_pParentDialog->OnClicked(this, pControl);
}

void CHnrjitContainer::OnKeyPress(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	if (m_pFocusControl && m_pFocusControl->IsVisible() && m_pFocusControl->IsEnabled())
	{
		m_pFocusControl->OnKeyPress(nChar, nRepCnt, nFlags);
	}
}

void CHnrjitContainer::OnKeyRelease(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	if (m_pFocusControl && m_pFocusControl->IsVisible() && m_pFocusControl->IsEnabled())
	{
		m_pFocusControl->OnKeyRelease(nChar, nRepCnt, nFlags);
	}
}

void CHnrjitContainer::OnMousePress(UINT nFlags, CPoint point)
{
	point -= GetLocation();
	for (int i = m_arrControls.GetCount() - 1; i >= 0; i--)
	{
		// 从最后一个控件响应起
		if (m_arrControls[i]->IsVisible())
		{
			// 控件可见，非透明
			if (m_arrControls[i]->GetGeometry().PtInRect(point))
			{
				if (m_arrControls[i]->IsEnabled())
				{
					// 控件可用
					if (m_pFocusControl == m_arrControls[i])
					{
						// 按下的控件之前按下过
						m_pFocusControl->OnMousePress(nFlags, point);
						return;
					}
					if (m_pFocusControl)
					{
						// 之前按下的控件
						m_pFocusControl->OnMouseRelease(nFlags, point);
						m_pFocusControl->OnKillFocus(m_arrControls[i]);
					}
					m_arrControls[i]->OnSetFocus(m_pFocusControl);
					m_pFocusControl = m_arrControls[i];
					m_arrControls[i]->OnMousePress(nFlags, point);
				}
				break;
			}
		}
	}
}

void CHnrjitContainer::OnMouseRelease(UINT nFlags, CPoint point)
{
	point -= GetLocation();
	for (int i = m_arrControls.GetCount() - 1; i >= 0; i--)
	{
		// 从最后一个控件响应起
		if (m_arrControls[i]->IsVisible())
		{
			// 控件可见，非透明
			if (m_arrControls[i]->GetGeometry().PtInRect(point))
			{
				if (m_arrControls[i]->IsEnabled())
				{
					// 控件可用
					if (m_pFocusControl == m_arrControls[i])
					{
						// 释放的控件之前按下过
						m_pFocusControl->OnMouseRelease(nFlags, point);
						return;
					}
				}
				break;
			}
		}
	}
	if (m_pFocusControl)
	{
		// 之前按下的控件不是当前释放的控件或没有按下任何控件
		m_pFocusControl->OnMouseRelease(nFlags, point);
	}
}

void CHnrjitContainer::OnMouseMove(UINT nFlags, CPoint point)
{
	point -= GetLocation();
	if (m_pFocusControl)
	{
		if (!m_pFocusControl->GetGeometry().PtInRect(point))
		{
			if (m_pFocusControl->m_isTriggered)
			{
				m_pFocusControl->m_isTriggered = FALSE;
				m_pFocusControl->Invalidate(m_pFocusControl->m_rcGeometry);
			}
		}
		else
		{
			m_pFocusControl->OnMouseMove(nFlags, point);
		}
	}
}

void CHnrjitContainer::Invalidate(const CRect& rcRect)
{
	m_pParentDialog->Invalidate(rcRect);
}

void CHnrjitContainer::DrawClipBox(HDC hdc, const CRect& rcClipBox)
{
	CRect rcIntersect;
	ATLASSERT(m_dwThreadID == GetCurrentThreadId());
	if (IsVisible() && rcIntersect.IntersectRect(GetGeometry(), rcClipBox))
	{
		if (!m_isTransparent)
		{
			// 非透明则贴图或填充
			if (m_hbmpBackImage)
			{
				HDC hSrcDC = CreateCompatibleDC(hdc);
				HGDIOBJ hOldBitmap = SelectObject(hSrcDC, m_hbmpBackImage);

				CPoint pointSrc = CPoint(rcIntersect.left - GetGeometry().left,
					rcIntersect.top - GetGeometry().top);
				BitBlt(hdc, rcIntersect.left, rcIntersect.top, rcIntersect.Width(), rcIntersect.Height(),
					hSrcDC, pointSrc.x, pointSrc.y, SRCCOPY);

				SelectObject(hSrcDC, hOldBitmap);
				DeleteDC(hSrcDC);
			}
			else
			{
				if (m_crBackColor != CLR_NONE)
				{
					SetBkColor(hdc, m_crBackColor);
					ExtTextOut(hdc, 0, 0, ETO_OPAQUE, rcIntersect, NULL, 0, NULL);
				}
				if (m_3dBorderColor != CLR_NONE)
				{
					int x = m_rcGeometry.left;
					int y = m_rcGeometry.top;
					int cx = m_rcGeometry.right - x;
					int cy = m_rcGeometry.bottom - y;

					SetBkColor(hdc, m_3dBorderColor);
					ExtTextOut(hdc, 0, 0, ETO_OPAQUE, CRect(x, y, x + (cx - 1), y + 1), NULL, 0, NULL);

					SetBkColor(hdc, m_3dBorderColor);
					ExtTextOut(hdc, 0, 0, ETO_OPAQUE, CRect(x, y, x + 1, y + (cy - 1)), NULL, 0, NULL);

					SetBkColor(hdc, m_3dBorderColor);
					ExtTextOut(hdc, 0, 0, ETO_OPAQUE, CRect((x + cx), y, (x + cx) - 1, y + cy), NULL, 0, NULL);

					SetBkColor(hdc, m_3dBorderColor);
					ExtTextOut(hdc, 0, 0, ETO_OPAQUE, CRect(x, (y + cy), x + cx, (y + cy) - 1), NULL, 0, NULL);
				}
			}
		}

		CPoint ptLocation = rcClipBox.TopLeft() - GetLocation();
		CRect rcOffset = CRect(ptLocation, rcClipBox.Size());
		for (size_t i = 0; i < m_arrControls.GetCount(); i++)
		{
			if (m_arrControls[i]->IsVisible() && rcIntersect.IntersectRect(m_arrControls[i]->GetGeometry(), rcOffset))
			{
				m_arrControls[i]->DrawControl(hdc);
			}
		}
	}
}
